package com.siyoumi.app.sys.service;

import com.siyoumi.app.sys.service.file.entity.FileUploadData;
import com.siyoumi.app.sys.vo.VoUploadFile;
import com.siyoumi.app.util.XQrCode;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.config.SysConfig;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.exception.XException;
import com.siyoumi.util.*;
import com.siyoumi.component.XApp;
import com.siyoumi.validator.XValidator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.List;

//通用api
@Slf4j
@Service
public class CommonApiServcie {
    public static CommonApiServcie getBean() {
        return XSpringContext.getBean(CommonApiServcie.class);
    }

    /**
     * 生成二维码
     */
    public BufferedImage qr(InputData inputData) {
        String txt = inputData.input("txt");
        Integer width = XStr.toInt(inputData.input("width", "300"));
        if (XStr.isNullOrEmpty(txt)) {
            throw new XException("txt miss");
        }

        return XQrCode.crateQRCode(txt, width, width);
    }


    /**
     * 图片链接换域名
     */
    public BufferedImage imgChange(InputData inputData) throws IOException {
        String url = inputData.input("url");
        if (XStr.isNullOrEmpty(url)) {
            throw new XException("url miss");
        }

        return XFile.toImgBuffer(url);
    }

    /**
     * base64保存图片
     */
    public XReturn imgBase64(String base64Str) {
        if (XStr.isNullOrEmpty(base64Str)) {
            return EnumSys.MISS_VAL.getR("缺少参数");
        }

        if (XStr.contains(base64Str, "base64,")) {
            String[] base64Arr = base64Str.split("base64,");
            base64Str = base64Arr[1];
        }

        byte[] fileByte = Base64.decodeBase64(base64Str);
        return saveFile(fileByte, "jpg");
    }

    /**
     * 通用上传文件
     *
     * @param vo              上传文件参数
     * @param fileExtenstions 允许上传文件后缀
     */
    public XReturn uploadFile(VoUploadFile vo, List<String> fileExtenstions) {
        FileUploadData data = FileUploadData.of(vo.getFile0(), fileExtenstions, SysConfig.getIns().getUploadFileSizeMax(), vo.getSaveFileDir());
        XReturn r = FileHandle.of(vo.getType()).uploadFile(data);
        if (r.ok()) {
            if (vo.getThumbnail() == 1) {
                String fileVal = r.getData("file_val");
                String fullPath = SysConfig.getIns().getUploadPath() + fileVal;
                //图片，并开启缩略图
                XReturn rThumb = CommonApiServcie.getBean().createThumbnailToReturn(new File(fullPath), vo.getThumbnail_width());
                r.setData("thumbnail", rThumb);
            }
        }
        return r;
    }

    /**
     * 通用上传文件
     *
     * @param file            post的文件流
     * @param fileExtenstions 允许上传文件后缀
     * @param fileSizeMaxM    允许上传的大小(m)
     */
    public XReturn uploadFile(MultipartFile file, List<String> fileExtenstions, Integer fileSizeMaxM, String saveFilePath) {
        if (file == null) {
            return EnumSys.FILE_EXISTS.getR();
        }

        String fileName = file.getOriginalFilename();
        String[] fileTypeData = fileName.split("\\.");
        String fileExt = "";
        if (fileTypeData.length > 1) {
            fileExt = fileTypeData[1];
        }
        log.debug("文件后缀：{}", fileExt);
        if (!fileExtenstions.contains(fileExt)) {
            return EnumSys.FILE_EXTENSTION.getR(XStr.concat("只能上传指定格式的文件[", String.join(",", fileExtenstions), "]"));
        }

        long fileSize = file.getSize();
        long fileSizeMax = fileSizeMaxM * 1024 * 1024;
        if (fileSize > fileSizeMax) {
            return EnumSys.FILE_SIZE.getR(XStr.concat("上传文件不能超", fileSizeMaxM + "M"));
        }

        byte[] fileBytes = new byte[0];
        try {
            fileBytes = file.getBytes();
        } catch (IOException e) {
            XReturn r = EnumSys.FILE_EXISTS.getR();
            r.setData("err_message", e.getMessage());
            XValidator.err(r);
        }

        XReturn r;
        if (XStr.isNullOrEmpty(saveFilePath)) {
            r = saveFile(fileBytes, fileExt);
        } else {
            r = saveFile(fileBytes, fileExt, saveFilePath);
        }
        String file_val = r.getData("file_val");
        r.setData("file_name", fileName);
        r.setData("file_size", fileSize);
        //后台数据一致
        HashMap<String, String> img = new HashMap<>();
        img.put("id", file_val);
        img.put("url", com.siyoumi.component.XApp.fileUrl(file_val));

        r.setData("img", img);

        return r;
    }

    @SneakyThrows
    public XReturn createThumbnailToReturn(File imgFile, int defaultWidth) {
        BufferedImage thumbnail = createThumbnail(imgFile, defaultWidth);
        if (thumbnail == null) {
            XValidator.err(20182, "缩略图生成失败");
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(thumbnail, "jpg", out);

        //new File(out.toByteArray());
        return saveFile(out.toByteArray(), "jpg");
    }

    @SneakyThrows
    public BufferedImage createThumbnail(File imageFile, int defaultWidth) {
        BufferedImage originalImage = ImageIO.read(imageFile);
        if (originalImage == null) {
            return null;
        }
        //int defaultWidth = 320;
        int width = originalImage.getWidth();
        int height = originalImage.getHeight();
        if (width < defaultWidth) {
            defaultWidth = width;
        }
        //同比例缩放
        height = (int) (((double) height / (double) width) * defaultWidth);
        width = defaultWidth;
        log.debug("img height: {}", height);
        log.debug("img width: {}", width);

        // 创建一个缩略图 BufferedImage 对象
        BufferedImage thumbnailImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 使用 Graphics2D 进行绘制操作
        Graphics2D graphics2D = thumbnailImage.createGraphics();
        //设置渲染提示
        graphics2D.setRenderingHint(
                //用于在缩放或变换图像时进行像素之间的插值 它影响图像的平滑度和细节保留程度
                RenderingHints.KEY_INTERPOLATION,
                //该值表示使用双线性插值算法进行图像的插值。双线性插值是一种平滑的插值方法
                //会在缩放时通过对周围像素的加权平均来计算新像素的值，以产生更平滑的图像。
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        //绘制缩略图
        graphics2D.drawImage(
                //原始图像
                originalImage,
                //绘制x轴的起点
                0,
                //y轴起点
                0,
                //x轴终点
                width,
                //y轴终点
                height,
                //观察者设置为空
                null);
        //释放画布资源
        graphics2D.dispose();

        return thumbnailImage;
    }

    public XReturn saveFile(byte[] fileByte, String fileExtensions) {
        String fileName = XStr.concat(XApp.getStrID(), ".", fileExtensions); //文件名
        String filePath = XStr.concat(com.siyoumi.component.XApp.getUploadFileDir(XHttpContext.getX()), fileName); //保存路径

        return saveFile(fileByte, fileExtensions, filePath);
    }

    /**
     * 文件保存
     *
     * @param fileByte       二进制
     * @param fileExtensions 文件后缀，如："png", "jpg", "gif", "jpeg"
     */
    public XReturn saveFile(byte[] fileByte, String fileExtensions, String saveFilePath) {
        log.debug("saveFilePath: {}", saveFilePath);

        //文件保存
        XFile.save(fileByte, saveFilePath);
        //D:\_job\job.java\_upload\wp/202207//895793403483127808.jpeg 去掉 D:\_job\job.java\_upload\
        String fileVal = saveFilePath.replace(SysConfig.getIns().getUploadPath(), "");

        XReturn r = XReturn.getR(0);
        r.setData("file_val", fileVal);
        r.setData("file_url", com.siyoumi.component.XApp.fileUrl(fileVal));

        return r;
    }

    @SneakyThrows
    static public File toFile(MultipartFile multipartFile) {
        String tmpFileDir = XApp.getUploadFileDir("_tmp", false); //临时目录
        String filePath = tmpFileDir + multipartFile.getOriginalFilename();
        log.debug("filePath: {}", filePath);
        File file = new File(filePath);
        FileUtils.writeByteArrayToFile(file, multipartFile.getBytes());
        return file;
    }
}
